package com.hibase.quartz.config.job;

import cn.hutool.core.exceptions.ExceptionUtil;
import com.alibaba.fastjson.JSON;
import com.hibase.quartz.entity.MdsJob;
import com.hibase.quartz.entity.MdsJobHandlerEntity;
import com.hibase.quartz.entity.MdsJobLog;
import com.hibase.quartz.service.MdsJobLogService;
import com.hibase.quartz.utils.JobHandlerScanner;
import com.hibase.quartz.utils.MdsJobUtils;
import lombok.extern.slf4j.Slf4j;
import org.quartz.Job;
import org.quartz.JobDataMap;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import java.lang.reflect.Method;
import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @Description: TODO
 * @Author: liuyunlei
 * @Date: 2020/11/24 16:20
 * @Version: 1.0
 */
@Component
@Slf4j
public class BaseJob implements Job {

    @Autowired
    private ApplicationContext applicationContext;

    @Autowired
    private MdsJobLogService mdsJobLogService;

    @Autowired
    private JobHandlerScanner jobHandlerScanner;

    @Value("${hibase.MdsJob.machineName:default}")
    public String machineName;

    private static BaseJob staticJob;

    @PostConstruct
    public void init() {

        staticJob = this;

        staticJob.applicationContext = this.applicationContext;

        staticJob.mdsJobLogService = this.mdsJobLogService;

        staticJob.jobHandlerScanner = this.jobHandlerScanner;

        staticJob.machineName = this.machineName;
    }

    /**
     * 核心方法,Quartz Job真正的执行逻辑.
     *
     * @param executorContext executorContext JobExecutionContext中封装有Quartz运行所需要的所有信息
     * @throws JobExecutionException execute()方法只允许抛出JobExecutionException异常
     */
    public void execute(JobExecutionContext executorContext) throws JobExecutionException {

        //JobDetail中的JobDataMap是共用的,从getMergedJobDataMap获取的JobDataMap是全新的对象
        JobDataMap map = executorContext.getMergedJobDataMap();

        MdsJob job = MdsJobUtils.JobDataMapToMdsJob(map);

        process(job);

    }

    public void process(MdsJob job){

        long startTime = System.currentTimeMillis();

        MdsJobLog jobLog = new MdsJobLog();

        jobLog.setStartTime(new Date());

        try {

            jobLog.setJobId(job.getId());

            jobLog.setJobName(job.getName());

            jobLog.setJobFinalExecutionArea(BaseJob.staticJob.machineName);

            jobLog.setJobType("定时任务");

            log.info("Running Job  : {} ", JSON.toJSONString(job));

            Object jobHandler = getJobHandler(job.getBeanName());

            Method execute = jobHandler.getClass().getMethod("execute", String.class);

            execute.invoke(jobHandler, job.getParameter());

            jobLog.setIsSuccess("TRUE");

        } catch (Exception e) {

            e.printStackTrace();

            jobLog.setIsSuccess("FAIL");

            jobLog.setErrorMsg(ExceptionUtil.getRootCauseMessage(e));

            log.error("Running Job fail , beause : {}", e.getMessage());
        }

        jobLog.setCompleteTime(new Date());

        long endTime = System.currentTimeMillis();

        jobLog.setTimeConsuming(new BigDecimal(endTime - startTime).multiply(new BigDecimal(0.001)));

        BaseJob.staticJob.mdsJobLogService.store(jobLog);

        log.info(">>>>>>>>>>>>> Running Job has been completed , cost time : {}ms\n ", (endTime - startTime)/1000);


    }


    private Object getJobHandler(String beanName) throws ClassNotFoundException {

        List<MdsJobHandlerEntity> jobHandlerEntityList = BaseJob.staticJob.jobHandlerScanner.getJobHandlerEntityList();

        List<MdsJobHandlerEntity> finalList = jobHandlerEntityList.stream()
                .filter(p -> p.getBeanName().equals(beanName)).collect(Collectors.toList());

        if (finalList.size() < 1) {

            throw new RuntimeException("根据beanName：" + beanName + "没有找到handler");

        }

        if (finalList.size() > 1) {

            throw new RuntimeException("根据beanName：" + beanName + "找到多个handler" + finalList.toString());

        }

        Class<?> aClass = Class.forName(finalList.get(0).getClassName());

        /**
         * 从 IOC容器拿到当前 类型 jobHandler实例
         *
         */
        Object bean = BaseJob.staticJob.applicationContext.getBean(aClass);

        if (bean == null) {

            throw new RuntimeException("在容器中没有找到实例！：" + finalList.get(0).getClassName());

        }

        return bean;
    }

}
